package game;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.MemoryImageSource;
import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.Timer;

public class Centipede extends Game {
    /** The amount of money in the small stack. */
    double smallStack;
    /** The amount of money in the large stack. */
    double largeStack;
    /** The amount the stacks grow each turn. */
    double increment;
    
	/** The amount of time we allow per decision, in seconds. */
	final int TURN_TIME = 60;

	/** The amount of time the subject spent thinking about their decision. */
	int playerThinkTime = 0;

    double p1_money_passed ;             /* Money that P1 passes */
    boolean p2_accepted = false ;     /* becomes true if P2 accepts the amount*/
    double money_won = 0 ;
    int count = 0 ;                   /* Keeps track of number of exchanges*/
    int max_allowed_counts ;          /* Maximum exchanges allowed*/
    String state = "1"  ;
    Random generator;                 /* Used for generating the probabilities */
	int totalTime = TURN_TIME;
    int secs = TURN_TIME, timeTaken=0, thinkSecs=0;
    Timer time = new Timer(1000, new TimeListener());
    Timer thinkTime = new Timer(1000, new ThinkTimeListener());
    Vector<String> totalTimeTaken = new Vector<String>(); // Currently not used.
    Vector<String> totalThinkTime = new Vector<String>(); // Currently not used.

	// Game log constants.
	final int GL_ACTION_PASS = 1;
	final int GL_ACTION_HOLD = 2;

    public Centipede(){
        super();
        /*Default assignments*/
        this.max_allowed_counts = 7;
        initComponents();
//        javax.swing.plaf.InternalFrameUI ui = this.getUI();
//        ((javax.swing.plaf.basic.BasicInternalFrameUI)ui).setNorthPane(null);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        lblStop.setVisible(true);
        lblPass.setVisible(true);
        this.setVisible(true);
        setLocation(screenSize.width/2-400, screenSize.height/2-300);

        runner.addMouseListener(new Centipede.CheckMouse());
        this.addMouseListener(new Centipede.CheckMouse());

        time.start();
        updateTimeLabel();
        hideMouse();
    }

    public Centipede (String params, int currentRep) {
        super();

		String paramPart[] = params.split(",");
        largeStack = Double.parseDouble(paramPart[2]);
        smallStack = Double.parseDouble(paramPart[3]);
        increment = Double.parseDouble(paramPart[4]);
        max_allowed_counts = Integer.parseInt(paramPart[5]);
		this.params = params;
		repTot = Integer.parseInt (paramPart[1]);
		repNum = currentRep;

        initComponents();
//        javax.swing.plaf.InternalFrameUI ui = this.getUI();
//        ((javax.swing.plaf.basic.BasicInternalFrameUI)ui).setNorthPane(null);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        l3.setText("Large stack: "+ String.format ("$%.2f", largeStack)
                + ", Small stack: " + String.format ("$%.2f", smallStack));
        lblStop.setVisible(true);
        lblPass.setVisible(true);
        this.setVisible(true);
        setLocation(screenSize.width/2-400, screenSize.height/2-300);

        runner.addMouseListener(new Centipede.CheckMouse());
        this.addMouseListener(new Centipede.CheckMouse());
		this.getGlassPane().addMouseListener(new Centipede.CheckMouse());

        time.start();
        updateTimeLabel();
        hideMouse();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        l1 = new javax.swing.JLabel();
        l2 = new javax.swing.JLabel();
        l3 = new javax.swing.JLabel();
        lblStop = new javax.swing.JLabel();
        lblPass = new javax.swing.JLabel();
        lblTime = new javax.swing.JLabel();

        setBackground(new java.awt.Color(255, 255, 255));
        setBorder(null);
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setMaximumSize(new java.awt.Dimension(800, 600));
        setMinimumSize(new java.awt.Dimension(800, 600));
        setPreferredSize(new java.awt.Dimension(800, 600));

        l1.setFont(new java.awt.Font("Calibri", 1, 28));
        l1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        l1.setText("You are Player 1");

        l2.setFont(new java.awt.Font("Calibri", 1, 32));
        l2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        l2.setText("What would you like to do ? ");

        l3.setFont(new java.awt.Font("Calibri", 1, 32));
        l3.setForeground(new java.awt.Color(0, 51, 255));
        l3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        l3.setText("You have $");

        lblStop.setFont(new java.awt.Font("Trebuchet MS", 1, 24));
        lblStop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/redStop.png"))); // NOI18N

        lblPass.setFont(new java.awt.Font("Trebuchet MS", 1, 24));
        lblPass.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblPass.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/greenPass.png"))); // NOI18N

        lblTime.setFont(new java.awt.Font("Calibri", 1, 36));
        lblTime.setForeground(new java.awt.Color(153, 102, 0));
        lblTime.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/hrGlass.png"))); // NOI18N
        lblTime.setText("3:00");

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .add(108, 108, 108)
                .add(lblStop)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 132, Short.MAX_VALUE)
                .add(lblPass)
                .add(94, 94, 94))
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(l2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                .addContainerGap())
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(l3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                .addContainerGap())
            .add(layout.createSequentialGroup()
                .add(lblTime, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 796, Short.MAX_VALUE)
                .add(4, 4, 4))
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(l1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(lblTime)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(l1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 76, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(24, 24, 24)
                .add(l3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 70, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(39, 39, 39)
                .add(l2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 76, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(59, 59, 59)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(lblStop)
                    .add(lblPass))
                .add(94, 94, 94))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    @Override
    public synchronized void addMouseListener(MouseListener l) {
        super.addMouseListener(l);
    }

    public void calculateResult(){
        secs = TURN_TIME;
		updateTimeLabel();
        generator = new Random();
        double prob_of_passing = 0 ;
        prob_of_passing = generator.nextDouble();

		ArrayList<ArrayList<String>> p1data
				= readCSVFile ("data/Centipede_data.csv");
		for (int row=1; row<p1data.size(); row++) {
			double p2Money = Double.parseDouble(p1data.get(row).get(0));
			double p2Prob = Double.parseDouble(p1data.get(row).get(1));

			// In case we reach the end of the data file without finding
			// a matching stack size and probability, we set default values.
			if (row == p1data.size()-1 && p2Money < largeStack) {
				p2Money = largeStack;
				p2Prob = 0.5;
			}

			//System.err.println ("[DEBUG]: p2Money=" + p2Money
			//		+ ", largeStack=" + largeStack);
			if (p2Money >= largeStack) {
				//System.err.println ("[DEBUG]: prob_of_passing="
				//		+ prob_of_passing + ", p2Prob=" + p2Prob);
				if (prob_of_passing < p2Prob) {
					state = "1";
					largeStack += increment;
					smallStack += increment;
					//System.err.println("[DEBUG]: P2 passed." );
					writeGameLog (playerId + ",1," + playerThinkTime + ","
						+ GL_ACTION_PASS + "," + GL_ACTION_PASS);
					playerThinkTime = 0;
					S1();
					break;
				}
				else {
					state = "3" ;  // Game ending state
					p2_accepted = true ;
					money_won = smallStack;
					writeGameLog (playerId + ",1," + playerThinkTime + ","
						+ GL_ACTION_PASS + "," + GL_ACTION_HOLD);
					playerThinkTime = 0;
					//System.err.println("[DEBUG]: P2 accepted." );
					S3() ;
					break ;
				}
			}
		}
    }

    private void hideMouse() {
        int[] pixels = new int[16 * 16];
        Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
        Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "invisibleCursor");
        this.getGlassPane().setCursor(transparentCursor);
		this.getGlassPane().setVisible(true);
        runner.setCursor(transparentCursor);
    }

    public void S1(){
        System.out.println("In S1()" ); /*a chance to pass in which case this message is not displayed*/
        l3.setText("Large stack: "+ String.format ("$%.2f", largeStack)
                + ", Small stack: " + String.format ("$%.2f", smallStack));

        if( count >= 1 ){                                           /*Since if count = 0 than that means P2 never got*/
            l2.setText("Player 2 passed. What would you like to do?");
        }
    }
    public void S2(){
        state="2";
        l2.setText(null);
        l1.setText(null);
        l3.setText("Waiting for Player 2...");
        lblStop.setVisible(false);
        lblPass.setVisible(false);
    }
    public void S3(){                                                           /*S3 Will have different messages based on different endings*/
        System.out.println("In S3()" );
        if( count >= max_allowed_counts ) {
            l2.setText("You have reached maximum number of passes.") ;
            totalTimeTaken.add("MaxLimit");
        }
        if( p2_accepted == true ){
            l2.setText("Player 2 stopped the game.") ;
            totalThinkTime.add("Stop");
        }
        else {
            l2.setText("You stopped the game.");
            timeTaken = totalTime - secs;
            totalTimeTaken.add(timeTaken+"s");
            totalTimeTaken.add("Stop");
        }
        secs=0;
        l3.setText("");
        lblStop.setVisible(false);
        lblPass.setVisible(false);
        //time.stop();
    }

	/**
	 * Updates the time label at the top.
	 */
	private void updateTimeLabel() {
		int min = secs/60;
		int sec = secs%60;
		lblTime.setText(min+":"+((sec<10)?"0":"")+sec);
	}

    class CheckMouse implements MouseListener{
        public void mousePressed(MouseEvent e) { hideMouse(); }
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
        public void mouseClicked(MouseEvent e) {
            int modifiers = e.getModifiers();
            if ((modifiers & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
                if(state.equals("3")){
//                    System.out.println("State: S" + state );
//
//                    setVisible(false);
//                    G.free = true;
                }
                if(state.equals("1")) {
                    System.out.println("State: S" + state );
                    state = "3";
                    /*if( count == 0 ){   /*This check is here since the P1  can accept the amount in */
                    //    money_won = largeStack; /*the first iteration and in that case p1_cumm_money = 0 */
                    //}
                    //else{
                    //    money_won = cumm_money;
                    //}
                    money_won = largeStack;
					writeGameLog (playerId + ",1," + playerThinkTime + ","
						+ GL_ACTION_HOLD + ",");
					playerThinkTime = 0;
                    S3() ;
                }
            }
            if ((modifiers & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) {
                if(state.equals("3")){
//
//                    setVisible(false);
//                    G.free = true;
                }
                if (state.equals("1")) {
                    System.out.println("State: S" + state );
                    if( count < max_allowed_counts ){
                        //cumm_money += 1 ;                      /* Potential money that p1 can own */
                        //p1_money_passed = cumm_money ;
                        largeStack += increment;
                        smallStack += increment;
                        count++ ;

                        Random rand = new Random();
                        thinkSecs = rand.nextInt(3) + 5;
                        totalThinkTime.add(thinkSecs+"s");
                        timeTaken = totalTime - secs;
                        totalTimeTaken.add(timeTaken+"s");
						
                        time.stop();
                        thinkTime.start();
                        S2();
                    }
                    else{
                        state = "3" ;
                        S3() ;
                        money_won = 0 ;
                    }
                }
            }
        }
    }


    class TimeListener implements ActionListener {
    	public void actionPerformed(ActionEvent e) {
    		secs--;
			playerThinkTime++;
            if(secs>=0) {
                updateTimeLabel();
            }
            if(secs==0) {
                //time.stop();

                state = "Next";
                lblStop.setVisible(false);
                lblPass.setVisible(false);
                l2.setText("Sorry, your time is up.");
				writeLog (playerId + ",1,\"" + params + "\"," + repNum
						+ "," + repTot + ",TimeOut,TimeOut");
                totalTimeTaken.add("TimeOut");
            }
            if(secs==-6) {
                time.stop();
                try{
                    System.out.println("money_Won: " + money_won) ;
                    
					double oppMoney = (money_won == largeStack ? smallStack
						: largeStack);
					writeLog (playerId + ",1,\"" + params + "\"," + repNum
						+ "," + repTot + ","
						+ String.format ("$%.2f", money_won) + ","
						+ String.format ("$%.2f", oppMoney));
                    totalMoneyWon += money_won ;
                    System.out.println("G.totalMoneyWon = " + totalMoneyWon) ;

                }catch(Exception ex){
                    ex.printStackTrace();
                    logError(ex);
                }
                state = "4" ;
                setVisible(false);
                free=true;
            }
    	}

    }

    class ThinkTimeListener implements ActionListener {
    	public void actionPerformed(ActionEvent e) {
    		thinkSecs--;
            if(thinkSecs==0) {
                thinkTime.stop();
                lblStop.setVisible(true);
                lblPass.setVisible(true);
				calculateResult();
                time.start();            
            }
    	}
    }

    public static void main(String args[]) {
        try {
            JFrame main = new JFrame();
            JDesktopPane dPane = new JDesktopPane();
            Centipede frame = new Centipede();
            main.setSize(820, 620);
            dPane.add(frame);
            main.add(dPane);
            main.setVisible(true);
            dPane.setVisible(true);
            frame.setSelected(true);
            frame.setVisible(true);
            } catch(Exception ex) {
            ex.printStackTrace();
            }

        
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel l1;
    private javax.swing.JLabel l2;
    private javax.swing.JLabel l3;
    private javax.swing.JLabel lblPass;
    private javax.swing.JLabel lblStop;
    private javax.swing.JLabel lblTime;
    // End of variables declaration//GEN-END:variables

}
